package biblioteca.servicio;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import biblioteca.dao.*;
import biblioteca.persistencia.*;
import com.google.appengine.api.datastore.Key;

import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import javax.annotation.PostConstruct;

@Service(value="UsuarioServicio")
public class UsuarioServicioImpl implements UsuarioServicio {

    private RolDao rolDao;
    private UsuarioDao usuarioDao;

    
    @Autowired
    @Required
    public void setRolDao(RolDao rolDao) {
        this.rolDao = rolDao;
    }

    @Autowired
    @Required
    public void setUsuarioDao(UsuarioDao usuarioDao) {
        this.usuarioDao = usuarioDao;
    }
    
    
    
    @PostConstruct
    @Override
    public void preload_usuarios() {
        
        usuarioDao.removeAll(Usuario.class);
        rolDao.removeAll(Rol.class);

        Usuario u1 = new Usuario();
        u1.setUsername("pepe");
        u1.setPassword("pepe");

        Usuario u2 = new Usuario();
        u2.setUsername("juan");
        u2.setPassword("juan");

        Usuario u3 = new Usuario();
        u3.setUsername("luis");
        u3.setPassword("luis");

        Rol r1 = new Rol();
        r1.setNombre("ROLE_ADMIN");

        Rol r2 = new Rol();
        r2.setNombre("ROLE_USER");
        
        rolDao.insert(r2);
        rolDao.insert(r1);
        
        addRol(u1, r1);
        addRol(u1, r2);
        addRol(u2, r2);
        addRol(u3, r2);


        create(u1);
        create(u2);
        create(u3);
        
      
    }

    @Override
    public void create(Usuario usuario) {
        usuarioDao.insert(usuario);
    }
    
    @Override
    public Usuario getUsuario(String idUsuario) {
        return usuarioDao.findByPK(Usuario.class, idUsuario);
    }
    
    public Collection<Rol> getRoles(Usuario usuario) {
        Collection<Rol> roles = new ArrayList<Rol>();
        for (Key keyRol : usuario.getRoles()) {
            Rol rol = rolDao.findByPK(Rol.class, keyRol);
            roles.add(rol);
        }
        return roles;
    }
    

    @Override
    public void addRol(Usuario usuario, Rol rol) {
        usuario.getRoles().add(rol.getId());
    }
    
    @Override
    public UserDetails loadUserByUsername(String nombreUsuario) throws UsernameNotFoundException, DataAccessException {
        
        Usuario usuario = usuarioDao.findByPK(Usuario.class, nombreUsuario);
        if (usuario == null) {
            throw new UsernameNotFoundException("User not found: " + nombreUsuario);
        } else {
            return makeUser(usuario);
        }
    }



    @Override
    public Usuario getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.isAuthenticated()) {
            String username = authentication.getName();
            return getUsuario(username);
        } else {
            return null;
        }
    }

    private org.springframework.security.core.userdetails.User makeUser(Usuario usuario) {
        return new org.springframework.security.core.userdetails.User(usuario.getUsername(), usuario.getPassword(),
                true, true, true, true, makeGrantedAuthorities(usuario));
    }

    private Collection<GrantedAuthority> makeGrantedAuthorities(Usuario usuario) {
        Collection<GrantedAuthority> result = new ArrayList<GrantedAuthority>();
        int i = 0;
        for (Rol rol : getRoles(usuario)) {
            result.add(new GrantedAuthorityImpl(rol.getNombre()));
        }
        return result;
    }
    
    
    @PreAuthorize("isAuthenticated()")
    @Override
    public boolean isAdmin() {
        final String ROLE_ADMIN = "ROLE_ADMIN";
        boolean isAdmin = false;
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        if (auth != null) {
            User user = ((User) auth.getPrincipal());
            Collection<GrantedAuthority> roles = user.getAuthorities();
            if (roles != null) {
                Iterator<GrantedAuthority> it = roles.iterator();
                while (!isAdmin && it.hasNext()) {
                    GrantedAuthority rol = it.next();
                    if (rol.getAuthority().equals(ROLE_ADMIN)) {
                        isAdmin = true;
                    }
                }
            }
        }
        return isAdmin;
    }

    @Override
    public void crearUsuario(Usuario usuario){
        usuarioDao.insert(usuario);
        
    }

    @Override
    public Collection<Usuario> getAllusuarios() {
        Collection<Usuario> usuarios = usuarioDao.getAll(Usuario.class);
        return usuarios;
    }

    @Override
    public Usuario buscarUsername(String username) {
        return usuarioDao.findByUsername(Usuario.class, username);       
    }
    
    @Override
    public Usuario buscar(String nick) {
        return usuarioDao.find(Usuario.class, nick);
    }

    @Override
    public void crearAdmin(Usuario u) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void anadirRol(Usuario usuario, Rol rol) {
        usuario.getRoles().add(rol.getId());
    }
    
    @Override
    public Rol buscarRol(String nombre){
        return rolDao.buscarRol(nombre);
    }
    
    
    
}
